#include "shader.h"

bool initGLSL()
{
	glewInit();
	if (GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader && GLEW_ARB_shadow)
	{
		printf("Ready for GLSL\n");
		return true;
	}
	else 
	{
		printf("No GLSL support\n");
		return false;
	}
}

////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////

Shader::Shader(char* vert_file, char *frag_file)
{
	handle = loadProgram(vert_file, frag_file);
}

Shader::Shader(char* frag_file)
{
    GLhandleARB frag = loadShader(frag_file, GL_FRAGMENT_SHADER_ARB);

	handle = glCreateProgramObjectARB();
	glAttachObjectARB(handle,frag);

	glLinkProgramARB(handle);
	//glUseProgramObjectARB(handle);
}

GLhandleARB Shader::getHandle()
{
    return handle;
}

void Shader::use()
{
	glUseProgram(handle);
}

void Shader::setUniform1i(char* name, GLuint val)
{
	GLuint tmp = glGetUniformLocationARB(handle, name);
	glUniform1iARB(tmp, val);
}

void Shader::setUniform3f(char* name, float x1, float x2, float x3)
{
	GLuint tmp = glGetUniformLocationARB(handle, name);
	glUniform3fARB(tmp, x1, x2, x3);
}

void Shader::setUniform3fv(char* name, int count, float *x1)
{
	GLuint tmp = glGetUniformLocationARB(handle, name);
	glUniform3fv(tmp, count, x1);
}

// Loading shader function
GLhandleARB loadShader(char* filename, unsigned int type)
{
	FILE *pfile;
	GLhandleARB handle;
	const GLcharARB* files[1];
	
	// shader Compilation variable
	GLint result;				// Compilation code result
	GLint errorLoglength ;
	char* errorLogText;
	GLsizei actualErrorLogLength;
	
	char buffer[400000];
	memset(buffer,0,400000);
	
	// This will raise a warning on MS compiler
	pfile = fopen(filename, "rb");
	if(!pfile)
	{
		printf("Sorry, can't open file: '%s'.\n", filename);
		exit(0);
	}
	
	fread(buffer,sizeof(char),400000,pfile);
	fclose(pfile);
	
	handle = glCreateShaderObjectARB(type);
	if (!handle)
	{
		//We have failed creating the vertex shader object.
		printf("Failed creating vertex shader object from file: %s.",filename);
		exit(0);
	}
	
	files[0] = (const GLcharARB*)buffer;
	glShaderSourceARB(
					  handle, //The handle to our shader
					  1, //The number of files.
					  files, //An array of const char * data, which represents the source code of theshaders
					  NULL);
	
	glCompileShaderARB(handle);
	
	//Compilation checking.
	glGetObjectParameterivARB(handle, GL_OBJECT_COMPILE_STATUS_ARB, &result);
	
	// If an error was detected.
	if (!result)
	{
		//We failed to compile.
		printf("Shader '%s' failed compilation.\n",filename);
		
		//Attempt to get the length of our error log.
		glGetObjectParameterivARB(handle, GL_OBJECT_INFO_LOG_LENGTH_ARB, &errorLoglength);
		
		//Create a buffer to read compilation error message
		errorLogText = (char *) malloc(sizeof(char) * errorLoglength);
		
		//Used to get the final length of the log.
		glGetInfoLogARB(handle, errorLoglength, &actualErrorLogLength, errorLogText);
		
		// Display errors.
		printf("%s\n",errorLogText);
		
		// Free the buffer malloced earlier
		free(errorLogText);
	}
	
	return handle;
}

GLhandleARB loadProgram(char* vert_filename, char* frag_filename)
{
	GLhandleARB prog;
	GLhandleARB vert = loadShader(vert_filename, GL_VERTEX_SHADER_ARB);
    GLhandleARB frag = loadShader(frag_filename, GL_FRAGMENT_SHADER_ARB);

	prog = glCreateProgramObjectARB();
	glAttachObjectARB(prog,frag);
	glAttachObjectARB(prog,vert);

	glLinkProgramARB(prog);
	glUseProgramObjectARB(prog);
	
	return prog;
}
